home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol04 / 02a / mdi / mdi3.c < prev   
C/C++ Source or Header  |  1988-12-06  |  19KB  |  679 lines

  1. /*
  2.  * MDI3.C - Menu Handling Routines
  3.  *
  4.  * LANGUAGE      : Microsoft C5.1
  5.  * MODEL         : medium
  6.  * ENVIRONMENT   : Microsoft Windows 2.1 SDK
  7.  * STATUS        : operational
  8.  *
  9.  * This module contains all the MDI code to handle the menus.  It
  10.  * creates as well as places and removes the document system menu from
  11.  * the MDI desktop menu bar.  It puts the title of a recently created
  12.  * or unhidden document on the WINDOW submenu and removes it when
  13.  * destroyed or hidden.  It switches the WINDOW submenu from one menu
  14.  * to another when switching between documents.  Finally it handles
  15.  * most of the keyboard interface to the menus.
  16.  *
  17.  * Developed by:
  18.  *   Geoffrey Nicholls
  19.  *   Kevin P. Welch
  20.  *
  21.  * (C) Copyright 1988
  22.  * Eikon Systems, Inc.
  23.  * 989 E. Hillsdale Blvd, Suite 260
  24.  * Foster City  CA  94404
  25.  *
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <windows.h>
  31.  
  32. #include "mdi.h"
  33.  
  34. /* Static variables */
  35. static FARPROC    lpMsgHook;        /* For the keyboard hooks */
  36. static FARPROC    lpOldMsgHook;
  37.  
  38. /* Global variables */
  39. int               iCurrentPopup = POP_NONE;  /* What menu is up */
  40. int               iNextPopup = POP_NONE;     /* What menuis next */
  41.  
  42. /* */
  43.  
  44. /*
  45.  * MdiZoomMenu( hwndChild ) : void;
  46.  *
  47.  *    hwndChild      Handle to document
  48.  *
  49.  * Adjust the document menu to include the MDI system menu.  This
  50.  * happens when a document is maximized.
  51.  *
  52.  */
  53.  
  54. void MdiZoomMenu( 
  55.    HWND        hwndChild )
  56. {
  57.    HBITMAP     hBitmap;          /* Handle to system menu bitmap */
  58.    HMENU       hmenuSystem;      /* Handle to system menu */
  59.    HWND        hwndMain;         /* Handle to MDI desktop */
  60.  
  61.    /* Change the menu */
  62.    hwndMain = GetParent( hwndChild );
  63.    hmenuSystem = MdiGetChildSysMenu( );
  64.    hBitmap = GetProp( hwndMain, PROP_SYSMENU );
  65.    ChangeMenu( GetProp( hwndChild, PROP_CHILDMENU ),
  66.       0,
  67.       ( LPSTR ) ( DWORD ) hBitmap,
  68.       hmenuSystem,
  69.       MF_BITMAP | MF_BYPOSITION | MF_INSERT | MF_POPUP );
  70. }
  71.  
  72. /* */
  73.  
  74. /*
  75.  * MdiRestoreMenu( hwndChild ) : void;
  76.  *
  77.  *    hwndChild      Handle to document
  78.  *
  79.  * Adjust the document menu by removing the MDI system menu.  This
  80.  * happens when a document is restored.
  81.  *
  82.  */
  83.  
  84. void MdiRestoreMenu(
  85.    HWND        hwndChild )
  86. {
  87.    /* Change the menu */
  88.    ChangeMenu( GetProp( hwndChild, PROP_CHILDMENU ),
  89.       0,
  90.       ( LPSTR ) NULL,
  91.       0,
  92.       MF_BYPOSITION | MF_REMOVE );
  93. }
  94.  
  95. /* */
  96.  
  97. /*
  98.  * MdiAppendWindowMenu( hwndChild ) : void;
  99.  *
  100.  *    hwndChild      Handle to document
  101.  *
  102.  * Add a newly created document's title to the WINDOW submenu.  The
  103.  * index is calculated by counting the number of items on the submenu.
  104.  *
  105.  */
  106.  
  107. void MdiAppendWindowToMenu( 
  108.    HWND        hwndChild )
  109. {
  110.    int         iIndex;           /* Numeric index for WINDOW menu */
  111.    char        szCurrent[50];    /* Text of title */
  112.    char        szText[50];       /* Text for menu */
  113.    HMENU       hmenuChild;       /* This document's menu */
  114.    HMENU       hmenuWindow;      /* WINDOW menu */
  115.    HWND        hwndMain;         /* Handle to MDI desktop */
  116.  
  117.    /* Get important info */
  118.    hwndMain = GetParent( hwndChild );
  119.    hmenuChild = GetProp( hwndChild, PROP_CHILDMENU );
  120.    hmenuWindow = GetProp( hwndMain, PROP_WINDOWMENU );
  121.  
  122.    /* Put in the separator */
  123.    if ( GetMenuItemCount( hmenuWindow ) == WINDOW_POS - 1 )
  124.    {
  125.       ChangeMenu( hmenuWindow,
  126.          0,
  127.          NULL,
  128.          0,
  129.          MF_APPEND | MF_SEPARATOR );
  130.    }
  131.  
  132.    /* Now add us to the WINDOW menu */
  133.    iIndex = GetMenuItemCount( hmenuWindow ) - WINDOW_POS + 1;
  134.    GetWindowText( hwndChild, szCurrent, sizeof( szCurrent ) );
  135.    sprintf( szText, "&%d. %s", iIndex, szCurrent );
  136.    ChangeMenu( hmenuWindow,
  137.       0,
  138.       szText,
  139.       GetProp( hwndChild, PROP_MENUID ),
  140.       MF_APPEND | MF_BYPOSITION | MF_CHECKED | MF_STRING );
  141. }
  142.  
  143. /* */
  144.  
  145. /*
  146.  * MdiReinsertWindowInMenu( hwndChild ) : void;
  147.  *
  148.  *    hwndChild      Handle to document
  149.  *
  150.  * Restore a hidden document's title to the WINDOW menu.  The index is
  151.  * calculated by counting the number of items on the submenu.
  152.  *
  153.  */
  154.  
  155. void MdiReinsertWindowInMenu( 
  156.    HWND        hwndChild )
  157. {
  158.    char        szCurrent[50];    /* Text of title */
  159.    char        szText[50];       /* Text for menu */
  160.    int         iIndex;           /* Numeric index for WINDOW menu */
  161.    HMENU       hmenuWindow;      /* WINDOW menu */
  162.    HWND        hwndMain;         /* Handle to MDI desktop */
  163.  
  164.    /* Get important info */
  165.    hwndMain = GetParent( hwndChild );
  166.    hmenuWindow = GetProp( hwndMain, PROP_WINDOWMENU );
  167.  
  168.    /* Put in the separator */
  169.    if ( GetMenuItemCount( hmenuWindow ) == WINDOW_POS - 1 )
  170.    {
  171.       ChangeMenu( hmenuWindow,
  172.          0,
  173.          NULL,
  174.          0,
  175.          MF_APPEND | MF_SEPARATOR );
  176.    }
  177.  
  178.    /* Prepare window string */
  179.    iIndex = GetMenuItemCount( hmenuWindow ) - WINDOW_POS + 1;
  180.    GetWindowText( hwndChild, szCurrent, sizeof( szCurrent ));
  181.    szCurrent[sizeof( szCurrent ) - 1] = '\0';
  182.    sprintf( szText, "&%d. %s", iIndex, szCurrent );
  183.  
  184.    /* Append us to the bottom */
  185.    ChangeMenu( hmenuWindow,
  186.       0,
  187.       szText,
  188.       GetProp( hwndChild, PROP_MENUID ),
  189.       MF_APPEND | MF_CHECKED | MF_STRING );
  190.  
  191.    /* All done */
  192.    DrawMenuBar( hwndMain );
  193. }
  194.  
  195. /* */
  196.  
  197. /*
  198.  * MdiRemoveWindowFromMenu( hwndChild, bWindowDying ) : void;
  199.  *
  200.  *    hwndChild      Handle to document
  201.  *    bWindowDying   Is the window being destroyed
  202.  *
  203.  * Remove the title of a about-to-be-hidden/destroyed document from
  204.  * the WINDOW submenu.  If the document's title wasn't the last item on
  205.  * the submenu then it updates the index for the documents that follow.
  206.  *
  207.  */
  208.  
  209. void MdiRemoveWindowFromMenu( 
  210.    HWND        hwndChild,
  211.    BOOL        bWindowDying )
  212. {
  213.    char        szCurrent[50];    /* Text of title */
  214.    char        szText[50];       /* Text for menu */
  215.    int         iIndex;           /* Numeric index for WINDOW menu */
  216.    HMENU       hmenuChild;       /* This document's menu */
  217.    HMENU       hmenuWindow;      /* WINDOW menu */
  218.    HWND        hwndMain;         /* Handle to MDI desktop */
  219.  
  220.    /* Get important info */
  221.    hwndMain = GetParent( hwndChild );
  222.    hmenuChild = GetProp( hwndChild, PROP_CHILDMENU );
  223.    hmenuWindow = GetProp( hwndMain, PROP_WINDOWMENU );
  224.  
  225.    /* Calculate our index */
  226.    for ( iIndex = WINDOW_POS;
  227.       iIndex < GetMenuItemCount( hmenuWindow );
  228.       iIndex++ )
  229.    {
  230.       if ( GetMenuItemID( hmenuWindow, iIndex )
  231.          == GetProp( hwndChild, PROP_MENUID ) )
  232.       {
  233.          /* Found us */
  234.          break;
  235.       }
  236.    }
  237.  
  238.    /* Delete us from everyone's menu */
  239.    ChangeMenu( hmenuWindow,
  240.       GetProp( hwndChild, PROP_MENUID ),
  241.       NULL,
  242.       NULL,
  243.       MF_BYCOMMAND | MF_DELETE );
  244.  
  245.    /* Adjust the rest of the window */
  246.    if ( GetMenuItemCount( hmenuWindow ) == WINDOW_POS )
  247.    {
  248.       /* Remove separator */
  249.       ChangeMenu( hmenuWindow,
  250.          WINDOW_POS - 1,
  251.          NULL,
  252.          0,
  253.          MF_DELETE | MF_BYPOSITION );
  254.    }
  255.    else
  256.    {
  257.       /* Shuffle menus down */
  258.       for ( ; iIndex < GetMenuItemCount( hmenuWindow ); iIndex++ )
  259.       {
  260.          GetMenuString( hmenuWindow,   
  261.             iIndex,
  262.             szCurrent,
  263.             sizeof( szCurrent ),
  264.             MF_BYPOSITION );
  265.          sprintf( szText,
  266.             "&%d. %s",
  267.             iIndex - WINDOW_POS + 1,
  268.             strchr( szCurrent, ' ' ) + 1 );
  269.          ChangeMenu( hmenuWindow,
  270.             iIndex,
  271.             szText,
  272.             GetMenuItemID( hmenuWindow, iIndex ),
  273.             MF_BYPOSITION | MF_CHANGE | MF_STRING | MF_UNCHECKED );
  274.       }
  275.    }
  276. }
  277.  
  278. /* */
  279.  
  280. /*
  281.  * MdiWindowMenu( hwndMain, mmenuChild, bAttach ) : void
  282.  *
  283.  *    hwndMain       Handle to MDI desktop
  284.  *    hmenuChild     Current document's menu
  285.  *    bAttach        Attach or detach
  286.  *
  287.  * Put or remove the WINDOW menu from the current document's menu.
  288.  *
  289.  */
  290.  
  291. void MdiWindowMenu(
  292.    HWND        hwndMain,
  293.    HMENU       hmenuChild,
  294.    BOOL        bAttach )
  295. {
  296.    HMENU       hmenuWindow;         /* WINDOW menu */
  297.  
  298.    hmenuWindow = GetProp( hwndMain, PROP_WINDOWMENU );
  299.    switch( bAttach )
  300.    {
  301.    case TRUE:
  302.       /* Attach */
  303.       ChangeMenu( hmenuChild,
  304.          0,
  305.          "&Window",
  306.          hmenuWindow,
  307.          MF_APPEND | MF_BYPOSITION | MF_POPUP );
  308.       break;
  309.  
  310.    case FALSE:
  311.       /* Detatch */
  312.       ChangeMenu( hmenuChild,
  313.          GetMenuItemCount( hmenuChild ) - 1,
  314.          ( LPSTR ) NULL,
  315.          0,
  316.          MF_BYPOSITION | MF_REMOVE );
  317.       break;
  318.    }
  319.    return;
  320. }
  321.  
  322. /* */
  323.  
  324. /*
  325.  * MdiInitSystemMenu( hwndChild ) : void
  326.  *
  327.  *    hwndChild      Handle to document
  328.  *
  329.  * Ensure that the MDI child's system menu is accurate.  This is not
  330.  * an issue when the child is maximized, as the submenu that appears
  331.  * on the menu bar is our own creation; however, when the system menu
  332.  * is in the upper left corner of the window, it is actually a windows
  333.  * system menu and contains the accelerator text for the <alt> key
  334.  * rather than the <ctrl> key.
  335.  *
  336.  */
  337.  
  338. void MdiInitSystemMenu( 
  339.    HWND        hwndChild )
  340. {
  341.    HMENU       hmenuSystem;      /* Handle to system menu */
  342.  
  343.    /* Get a copy of the system menu */
  344.    hmenuSystem = GetSystemMenu( hwndChild, FALSE );
  345.  
  346.    /* Initialize system menu */
  347.    ChangeMenu( hmenuSystem,
  348.       SC_RESTORE,
  349.       "&Restore    Ctrl+F5",
  350.       SC_RESTORE,
  351.       GetProp( GetParent( hwndChild ), PROP_ZOOM )
  352.          ? MF_BYCOMMAND | MF_CHANGE | MF_STRING
  353.          : MF_BYCOMMAND | MF_CHANGE | MF_GRAYED | MF_STRING );
  354.    ChangeMenu( hmenuSystem,
  355.       SC_MOVE,
  356.       "&Move       Ctrl+F7",
  357.       SC_MOVE,
  358.       MF_BYCOMMAND | MF_CHANGE | MF_STRING );
  359.    ChangeMenu( hmenuSystem,
  360.       SC_SIZE,
  361.       "&Size       Ctrl+F8",
  362.       SC_SIZE,
  363.       MF_BYCOMMAND | MF_CHANGE | MF_STRING );
  364.    ChangeMenu( hmenuSystem,
  365.       SC_MINIMIZE,
  366.       ( LPSTR ) NULL,
  367.       SC_MINIMIZE,
  368.       MF_BYCOMMAND | MF_DELETE );
  369.    ChangeMenu( hmenuSystem,
  370.       SC_MAXIMIZE,
  371.       "Ma&ximize   Ctrl+F10",
  372.       SC_MAXIMIZE,
  373.       MF_BYCOMMAND | MF_CHANGE | MF_STRING );
  374.    ChangeMenu( hmenuSystem,
  375.       SC_CLOSE,
  376.       "&Close      Ctrl+F4",
  377.       SC_CLOSE,
  378.       MF_BYCOMMAND | MF_CHANGE | MF_STRING );
  379. }
  380.  
  381. /* */
  382.  
  383. /*
  384.  * MdiGetChildSysMenu() : HMENU;
  385.  *
  386.  *
  387.  * Create a document system menu.  This menu is only used when the
  388.  * document is maximized.  Otherwise the default system menu is used
  389.  * and the text modified at WM_INITMENU.
  390.  *
  391.  */
  392.  
  393. HMENU MdiGetChildSysMenu( void )
  394. {
  395.    HMENU       hmenuSystem;      /* Handle to system menu */
  396.  
  397.    /* Change the menu */
  398.    hmenuSystem = CreateMenu( );
  399.    ChangeMenu( hmenuSystem, 0,
  400.       "&Restore    Ctrl+F5",
  401.       IDM_RESTORE,
  402.       MF_APPEND | MF_STRING );
  403.    ChangeMenu( hmenuSystem, 0,
  404.       "&Move       Ctrl+F7",
  405.       IDM_MOVE,
  406.       MF_APPEND | MF_GRAYED | MF_STRING );
  407.    ChangeMenu( hmenuSystem, 0,
  408.       "&Size       Ctrl+F8",
  409.       IDM_SIZE,
  410.       MF_APPEND | MF_GRAYED | MF_STRING );
  411.    ChangeMenu( hmenuSystem, 0,
  412.       "Ma&ximize   Ctrl+F10",
  413.       IDM_MAXIMIZE,
  414.       MF_APPEND | MF_STRING );
  415.    ChangeMenu( hmenuSystem, 0,
  416.       ( LPSTR ) NULL,
  417.       0,
  418.       MF_APPEND | MF_SEPARATOR );
  419.    ChangeMenu( hmenuSystem, 0,
  420.       "&Close      Ctrl+F4",
  421.       IDM_CLOSE,
  422.       MF_APPEND | MF_STRING );
  423.    return hmenuSystem;
  424. }
  425.  
  426. /* */
  427.  
  428. /*
  429.  * MdiCreateChildSysBitmap( hwndMain ) : HBITMAP;
  430.  *
  431.  *    hwndMain       Handle to MDI desktop
  432.  *
  433.  * Create a bitmap for the document system menu (the bitmap that looks
  434.  * like a '-'.  The system already has one, so we use it; however there
  435.  * are two parts to the system bitmap:  one half for parent system menu
  436.  * bitmaps and the other half for the child system menu bitmap.  This
  437.  * routine makes a memory DC for the two part bitmap, another memory DC
  438.  * to receive the second (and smaller) half, creates a half sized
  439.  * bitmap, and bitblt()s the smaller bitmap into the half sized bitmap
  440.  * of ours.
  441.  *
  442.  */
  443.  
  444. HBITMAP MdiCreateChildSysBitmap( 
  445.    HWND        hwndMain )
  446. {
  447.    BOOL        bResult;          /* Do we have a good bitmap made? */
  448.    HDC         hDC;              /* DC for MDI desktop */
  449.    HDC         hMemFullDC;       /* Mem DC for both system bitmaps */
  450.    HDC         hMemHalfDC;       /* Mem DC for small system bitmap */
  451.    BITMAP      Bitmap;           /* Bitmap information */
  452.    HBITMAP     hFullBitmap;      /* Handle to both system bitmaps */
  453.    HBITMAP     hHalfBitmap;      /* Handle to copy of small bitmap */
  454.    int         iBitmapWidth;     /* Width of system bitmaps */
  455.    int         iBitmapHeight;    /* Height of system bitmaps */
  456.  
  457.    bResult = FALSE;
  458.    hFullBitmap = LoadBitmap( NULL, MAKEINTRESOURCE( OBM_CLOSE ) );
  459.    if ( hFullBitmap )
  460.    {
  461.       GetObject( hFullBitmap, sizeof( Bitmap ), ( LPSTR ) &Bitmap );
  462.       iBitmapWidth = Bitmap.bmWidth / 2;
  463.       iBitmapHeight = GetSystemMetrics( SM_CYMENU );
  464.       hDC = GetDC( hwndMain );
  465.       if ( hDC )
  466.       {
  467.          hMemFullDC = CreateCompatibleDC( hDC );
  468.          if ( hMemFullDC )
  469.          {
  470.             SelectObject( hMemFullDC, hFullBitmap );
  471.             hMemHalfDC = CreateCompatibleDC( hDC );
  472.             if ( hMemHalfDC )
  473.             {
  474.                hHalfBitmap = CreateCompatibleBitmap( hMemHalfDC,
  475.                   iBitmapWidth, iBitmapHeight );
  476.                if ( hHalfBitmap )
  477.                {
  478.                   SelectObject( hMemHalfDC, hHalfBitmap );
  479.                   PatBlt( hMemHalfDC,
  480.                      0, 0,
  481.                      iBitmapWidth, iBitmapHeight,
  482.                      WHITENESS );
  483.                   bResult = BitBlt( hMemHalfDC,
  484.                      0, 0,
  485.                      iBitmapWidth, iBitmapHeight,
  486.                      hMemFullDC,
  487.                      iBitmapWidth, 0,
  488.                      SRCCOPY );
  489.                }
  490.                DeleteDC( hMemHalfDC );
  491.             }
  492.             DeleteDC( hMemFullDC );
  493.          }
  494.          ReleaseDC( hwndMain, hDC );
  495.       }
  496.       DeleteObject( hFullBitmap );
  497.    }
  498.    return bResult ? hHalfBitmap : NULL;
  499. }
  500.  
  501. /* */
  502.  
  503. /*
  504.  * MdiSetMenuKeyhook( hInst ) : void;
  505.  *
  506.  *    hInst          Current instance handle
  507.  *
  508.  * Install our keyboard hook.  This allows document system menus
  509.  * to be part of the keyboard interface to menus.
  510.  *
  511.  */
  512.  
  513. void MdiSetMenuKeyHook(
  514.    HANDLE      hInst )
  515. {
  516.    lpMsgHook = MakeProcInstance( ( FARPROC ) MdiMsgHook, hInst );
  517.    lpOldMsgHook = SetWindowsHook( WH_MSGFILTER, lpMsgHook );
  518. }
  519.  
  520. /* */
  521.  
  522. /*
  523.  * MdiMenuMessageLoopUpdate( hwndMain ) : void;
  524.  *
  525.  *    hwndMain       Handle to MDI desktop
  526.  *
  527.  * Activate the correct popup menu if the right or left arrow key
  528.  * was hit and the document's system menu is involved.  Notice that
  529.  * instead of doing this when the actual event occured, we wait until
  530.  * DispatchMessage() is done.  This way the currently popped up menu
  531.  * closes down in an orderly fashion before the next popup menu is
  532.  * popped up.
  533.  *
  534.  */
  535.  
  536. void MdiMenuMessageLoopUpdate( 
  537.    HWND        hwndMain )
  538. {
  539.    int         iOldNext;         /* Preserve current state info */
  540.    HWND        hwndActive;       /* Current document window */
  541.  
  542.    /* With no messages, we're assured that no menu is popped up */
  543.    iCurrentPopup = POP_NONE;
  544.  
  545.    if ( iNextPopup != POP_NONE )
  546.    {
  547.       /*
  548.        * This sequence is used because the SendMessage() call
  549.        * could generate reentrancy problems.
  550.        */
  551.       iOldNext = iNextPopup;
  552.       iNextPopup = POP_NONE;
  553.  
  554.       /* Hilite the proper popup */
  555.       hwndActive = GetProp( hwndMain, PROP_ACTIVE );
  556.       switch( iOldNext )
  557.       {
  558.       case POP_MAINSYS:
  559.          SendMessage( hwndMain,
  560.             WM_SYSCOMMAND,
  561.             SC_KEYMENU,
  562.             (DWORD) ' ');
  563.          break;
  564.  
  565.       case POP_MAIN1ST:
  566.          SendMessage( hwndMain,
  567.             WM_SYSCOMMAND,
  568.             SC_KEYMENU,
  569.             (DWORD) 'F');
  570.          break;
  571.  
  572.       case POP_CHILDSYS:
  573.          if ( hwndActive )
  574.          {
  575.             SendMessage(
  576.                hwndActive,
  577.                WM_SYSCOMMAND,
  578.                SC_KEYMENU,
  579.                (DWORD) '-');
  580.          }
  581.          break;
  582.       }
  583.    }
  584. }
  585.  
  586. /* */
  587.  
  588. /*
  589.  * MdiMsgHook( iContext, wCode, lParam ) : LONG;
  590.  *
  591.  *    iContext       What is the key message's destination
  592.  *    wCode          Will this key result in an action
  593.  *    lParm          Pointer to the key message
  594.  *
  595.  * Watch for left and right arrows when a menu is hilited.  This allows
  596.  * these keys to move to the document's system menu between the MDI
  597.  * desktop's system menu and the FILE menu.  Notice that we only set
  598.  * variables here, we don't perform the actions.
  599.  *
  600.  */
  601.  
  602. LONG FAR PASCAL MdiMsgHook( 
  603. int         iContext,
  604. WORD        wCode,
  605. LONG        lParam )
  606. {
  607.    BOOL        bCancelMenu = FALSE;
  608.    BOOL        bActive;
  609.    BOOL        bZoomed;
  610.    HWND        hwndMain;
  611.    WORD        wKey;
  612.    MSG FAR     *lpMsg;
  613.  
  614.    lpMsg = ( MSG FAR * ) lParam;
  615.    hwndMain = lpMsg->hwnd;
  616.    if ( GetProp( hwndMain, PROP_ISMDI ) )
  617.    {
  618.       hwndMain = GetParent( hwndMain );
  619.    }
  620.    wKey = lpMsg->wParam;
  621.    if ( iContext == MSGF_MENU
  622.       && wCode == HC_ACTION
  623.       && GetProp( hwndMain, PROP_ACTIVE )
  624.       && !GetProp( hwndMain, PROP_ZOOM )
  625.       && lpMsg->message == WM_KEYDOWN
  626.       && wKey == VK_LEFT || wKey == VK_RIGHT )
  627.    {
  628.       /* we have a left or right arrow key in the menus */
  629.       switch( iCurrentPopup )
  630.       {
  631.       case POP_CHILDSYS:
  632.          iNextPopup = ( wKey == VK_LEFT ? POP_MAINSYS : POP_MAIN1ST );
  633.          bCancelMenu = TRUE;
  634.          break;
  635.  
  636.       case POP_MAINSYS:
  637.          if ( wKey == VK_RIGHT )
  638.          {
  639.             iNextPopup = POP_CHILDSYS;
  640.             bCancelMenu = TRUE;
  641.          }
  642.          break;
  643.  
  644.       case POP_MAIN1ST:
  645.          if ( wKey == VK_LEFT )
  646.          {
  647.             iNextPopup = POP_CHILDSYS;
  648.             bCancelMenu = TRUE;
  649.          }
  650.          break;
  651.       }
  652.  
  653.       /* Do we want this to go through? */
  654.       if ( bCancelMenu )
  655.       {
  656.          lpMsg->wParam = VK_CANCEL;
  657.       }
  658.    }
  659.    /* Pass it on */
  660.    return DefHookProc( iContext,
  661.       wCode,
  662.       lParam,
  663.       ( FARPROC FAR * ) &lpOldMsgHook );
  664. }
  665.  
  666. /* */
  667.  
  668. /*
  669.  * MdiFreeMenuKeyhook( void ) : void
  670.  *
  671.  * Free the procedure instance required for the keyboard hook.
  672.  *
  673.  */
  674.  
  675. void MdiFreeMenuKeyHook( void )
  676. {
  677.    FreeProcInstance( lpMsgHook );
  678. }
  679.